iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 24
2
Software Development

iOS 三十天上架記帳 APP系列 第 24

Money Mom - 實做統計功能 - 標籤快篩

  • 分享至 

  • xImage
  •  

有了折線圖後,我們接下來要實做標籤篩選的功能,讓使用者可以依照標籤檢視折線圖。

標籤 Migration

沒錯,又要做 Migration!因為之前的結構,標籤是直接用 Transformable 儲存字串集合,但如果要能夠輕易篩選,我們需要將標籤獨立出來,並透過 Relationship 的方式關聯。

建立 Many-to-Many 關聯

在 Core Data 中,要建立 Many-to-Many 關聯,必須在兩邊的 Entity 都設定 To-Many,並互相設定對方為 Destination/Inverse,否則 Core Data 不會建立 Many-To-Many 的資料關聯,也因為這樣,如果在 Migration 中,有某些收支記錄、快速記帳有關聯到相同的標籤時,Core Data 就只會幫我們建立第一個遇到的關聯,剩下後面重複的都會消失,身為專業工程師,讓使用者的資料消失是會影響職業生涯,非常嚴重的問題。因此在處理資料時,需格外小心。

實做 NSEntityMigrationPolicy

前面在轉換收支記錄統計時,有實做過 NSEntityMigrationPolicy,但這次比較不一樣的是,需要我們特別處理的部分,是「關聯」的部分,因此這次我們必須提供 createRelationships(forDestination:in:manager) 方法,協助 Core Data 處理資料中間的關聯。

Core Data - The Migration Process 中,Core Data 有簡單說明 Migration 的三個步驟:

  1. 建立實體:從舊資料轉換到新資料結構
  2. 重建關聯:擁有新資料結構後,重建新資料的關聯(也是本次主角)
  3. 驗證儲存:提供最後一個驗證的階段,一切都沒問題後,就會儲存並取代舊資料

延續上述,我們這次專心處理標籤的關聯,因此我們只實做第二階段「重建關聯」相關邏輯。

邏輯順序大概是:

  1. 找出 destination 對應的 source 實體
  2. 找出 source 實體的標籤集合(Set<String>
  3. 若 destination 中未建立該標籤,則新增該標籤
  4. 建立 destination 實體的標籤關聯

程式碼如下:

let sTransaction = manager.sourceInstances(forEntityMappingName: mapping.name, destinationInstances: [dInstance]).first!

let tagNames = sTransaction.value(forKey: "tags") as! Set<String>

var tags = Set<NSManagedObject>()

tagNames.forEach { tagName in
    tags.insert(createDestinationTag(named: tagName, manager: manager))
}

dInstance.setValue(tags, forKey: "tags")
private func createDestinationTag(named tagName: String, manager: NSMigrationManager) -> NSManagedObject {
    let request = NSFetchRequest<NSManagedObject>(entityName: String(describing: Tag.self))
    request.predicate = NSPredicate(format: "\(#keyPath(Tag.name)) = %@", argumentArray: [tagName])

    let tags = try! manager.destinationContext.fetch(request)

    if tags.isEmpty {
        let tag = NSEntityDescription.insertNewObject(forEntityName: String(describing: Tag.self), into: manager.destinationContext)
        tag.setValue(tagName, forKey: "name")

        return tag
    }

    return tags.first!
}

篩選標籤

使用者點選標籤後,會即時更新折線圖的資料,流程如下:

  1. 從 Core Data 中取得所有標籤
  2. 使用者點擊標籤後,從 Core Data 中找出含有該標籤的 TransactionStats
  3. 重新畫折線圖

如何篩選關聯?

用 NSPredicate,語法可以參照這篇文章,邏輯是只要 TransactionStats 的標籤中,有包含使用者選到的標籤都要被抓出來,如下:

fetchedResultsController.fetchRequest.predicate = NSPredicate(format: "ANY \(#keyPath(TransactionStats.tags)) IN %@", argumentArray: [selectedTags])
try! fetchedResultsController.performFetch()

展示

程式碼:GitHub

主要想做的功能大概有做到,接下來要把 Issue 解一解,然後整理下程式,送審囉!


上一篇
Money Mom - 實做統計功能 - 折線圖 Part ∞
下一篇
Money Mom - v0.2.0 上架前重整規劃
系列文
iOS 三十天上架記帳 APP30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
zdey
iT邦新手 5 級 ‧ 2018-01-12 11:46:37

有DEMO有推

我要留言

立即登入留言